package com.qax.task.cron.support;

import com.qax.task.cron.*;
import org.apache.logging.log4j.core.util.Assert;

import java.util.*;


/**
 * <BR>Helper bean for registering tasks with a {@link TaskScheduler},
 * typically using cron expressions.<BR/>
 *
 * @author leiliang
 */
public class ScheduledTaskRegistrar {

    private TaskScheduler taskScheduler = new ThreadPoolTaskScheduler();

    private final Map<Task, ScheduledTask> unresolvedTasks = new HashMap<>(16);

//    private final Set<ScheduledTask> scheduledTasks = new LinkedHashSet<>(16);

    private List<CronTask> cronTasks;

    /**
     * Add a Runnable task to be triggered per the given cron expression.
     */
    public void addCronTask(Runnable task, String expression) {
        addCronTask(new CronTask(task, expression));
    }

    /**
     * Add a {@link CronTask}.
     */
    public void addCronTask(CronTask task) {
        if (this.cronTasks == null) {
            this.cronTasks = new ArrayList<>();
        }
        this.cronTasks.add(task);
    }

    /**
     * Schedule the specified cron task, either right away if possible
     * or on initialization of the scheduler.
     * @return a handle to the scheduled task, allowing to cancel it
     * (or {@code null} if processing a previously registered task)
     * @since 4.3
     */
    public ScheduledTask scheduleCronTask(CronTask task) throws TaskRejectedException {
        ScheduledTask scheduledTask = this.unresolvedTasks.remove(task);
        boolean newTask = false;
        if (scheduledTask == null) {
            scheduledTask = new ScheduledTask(task);
            newTask = true;
        }
        if (this.taskScheduler != null) {
            scheduledTask.future = this.taskScheduler.schedule(task.getRunnable(), task.getTrigger());
        }
        else {
            addCronTask(task);
            this.unresolvedTasks.put(task, scheduledTask);
        }
        return (newTask ? scheduledTask : null);
    }


    /**
     * Set the {@link TaskScheduler} to register scheduled tasks with for client.
     */
    public void setTaskScheduler(TaskScheduler taskScheduler) {
        Assert.isNonEmpty(taskScheduler);
        this.taskScheduler = taskScheduler;
    }

}
